/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */

package org.vacoor.nothing.web.captcha.support;


import org.vacoor.nothing.web.captcha.ImageCaptcha;

import javax.imageio.ImageIO;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;

/**
 * 一个简单的 gimpy 验证码实现
 * @author vacoor
 */
public class SimpleGimpy implements ImageCaptcha {
    protected transient BufferedImage challenge;
    private final Serializable id;
    private final String response;
    private boolean caseSensitive;                  /* 是否大小写敏感 */
    private boolean hasChallengeBeenCalled = false; /* 是否获取过 challenge */
    private Date effectiveDate;


    protected SimpleGimpy(String id, BufferedImage challenge, String response, boolean caseSensitive) {
        this.id = id;
        this.challenge = challenge;
        this.response = response;
        this.caseSensitive = caseSensitive;
    }

    public Serializable getId() {
        return id;
    }

    /**
     * @return the image challenge
     */
    @Override
    public final BufferedImage getChallenge() {
        hasChallengeBeenCalled = true;
        effectiveDate = new Date();
        return challenge;
    }

    @Override
    public boolean validate(String response) {
        return null != response ? (caseSensitive ? response.equals(this.response) : response.equalsIgnoreCase(this.response)) : false;
    }


    public final void disposeChallenge() {
        this.challenge = null;
    }

    public boolean hasGetChallengeBeenCalled() {
        return hasChallengeBeenCalled;
    }

    @Override
    public Date getEffectiveDate() {
        return this.effectiveDate;
    }

    /* ********************
     *
     * ****************** */

    /**
     * This method have to be implemented in order to serialize the image challenge to JPEG format
     *
     * @param out The target outputStream in which the captcha will be serialized
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream out) throws IOException {

        // Serialize captcha fields with default method
        out.defaultWriteObject();

        // If the challenge has not been disposed
        if (this.challenge != null) {
            // use png encoding
            ImageIO.write(this.challenge, "png", new MemoryCacheImageOutputStream(out));
        }
    }

    /**
     * This method have to be implemented in order to unserialize the image challenge from JPEG format
     *
     * @param in The source inputStream from which the captcha will be unserialized
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {

        // UnSerialize captcha fields with default method
        in.defaultReadObject();

        try {

            this.challenge = ImageIO.read(new MemoryCacheImageInputStream(in));
        } catch (IOException e) {
            if (!hasChallengeBeenCalled) {
                // If the getChallenge method has not been called the challenge should be available for unmarhslling.
                // In this case, the thrown Exception is not related to the dispose status 
                throw e;
            }
        }
    }
}
